﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace Tzync
{
    /***************************************************************************************************/
    /* This Class acts as an interface between the metadata files and the Tree of Nodes in the program */
    /***************************************************************************************************/

    public class MetaData
    {        
        int logFileCreateCounter, nodeIndex, flag;
        private String rootFolder;
        private String logFilePath = Directory.GetCurrentDirectory();
        private List<TreeNode> arrNodes = new List<TreeNode>();
        private List<long> DirectorySize = new List<long>();
        private SystemType systemName;
        private Profile profile;

        //Constructor loads the address of the folder selected

        public MetaData(Profile p)
        {            
            profile = p;            
            systemName = p.SystemName;
            if (systemName == SystemType.Host)
                rootFolder = profile.RootAddressA;
            else
                rootFolder = profile.RootAddressB;

            flag = 0;            
            logFileCreateCounter = 0;
        }

        //Function to read from the logFile (if it exists) or create one and Create Tree of TreeNodes.

        public void readFromFile()
        {
            //load from file. create a Node
            TextReader tr;
            String input = "";
            TreeNode n;
            FileStream fs;
            DirectoryInfo D;

            String metaDataPath = Path.Combine(profile.ProfilePath, "MetaData");

            if (File.Exists(metaDataPath))
            {
                // open file
                tr = new StreamReader(metaDataPath);
                while ((input = tr.ReadLine()) != null)
                {
                    if (input.Trim().Length != 0)
                    {
                        n = new TreeNode(input);
                        arrNodes.Add(n);
                    }
                }
                // close the stream
                tr.Close();
            }

            else
            {
                fs = File.Create(metaDataPath);
                fs.Close();
                D = new DirectoryInfo(@rootFolder);
                DFS(D, 0);
                writeToFile();
            }
        }

        /*********************************************************/
        /* Accessory Functions for the data members of the class */
        /*********************************************************/

        public TreeNode getNode(int index)
        {
            if (index < arrNodes.Count)
                return arrNodes[index];
            else return null;
        }

        public void setNode(int index, TreeNode n)
        {
            if (index < arrNodes.Count)
                arrNodes[index] = n;
        }

        public void addNode(TreeNode n)
        {
            arrNodes.Add(n);
        }

        public List<TreeNode> getAllNodes()
        {
            return arrNodes;
        }

        /**************************************************************/
        /* Accessory Functions for the data members of the class end !*/
        /**************************************************************/

        //Description     : Function to Create the log File the first time.
        //Pre-Conditions  : Parent is a valid index of arrNode array, Directory D exists.
        //Post-Conditions : A Tree of TreeNode Class is created for the FIRST RUN of the software from system.       

        public int DFS(DirectoryInfo D, int parent)
        {
            int cur = logFileCreateCounter, child;
            DirectoryInfo[] subDirectories = D.GetDirectories();
            FileInfo[] subFiles = D.GetFiles();
            String DString = createEntry(D, parent, subDirectories.Count(), subFiles.Count());
            TreeNode n = new TreeNode(DString), n1;
            arrNodes.Add(n);

            for (int i = 0; i < subFiles.Count(); i++)
            {
                DString = logFileCreateCounter.ToString() + "|"; ;
                //add each File info  
                DString = DString + subFiles[i].FullName + "|" + "|" + "1,0" + "|" + subFiles[i].Length + "|" + "0,0" + "|";
                DString = DString + "0" + "|" + subFiles[i].LastWriteTime + "|" + subFiles[i].LastWriteTime + "|";
                DString = DString + cur.ToString() + "|";
                n1 = new TreeNode(DString);
                arrNodes.Add(n1);
                arrNodes[cur].addChild(logFileCreateCounter);
                logFileCreateCounter++;
            }

            for (int i = 0; i < subDirectories.Count(); i++)
            {
                child = DFS(subDirectories[i], cur);
                arrNodes[cur].addChild(child);
            }

            arrNodes[cur].addChild(-1);
            n.setChilds(n.dynamicChildList);
            return cur;
        }

        //Description     : Function to create a logFile entry for a Directory
        //Pre-Conditions  : Parent is a valid arrNode index, Directory D exists
        //Post-Conditions : A string is created to be given to TreeNode class to create a Tree node from it      

        private String createEntry(DirectoryInfo D, int parent, int f, int d)
        {
            long size = CalculateDirectorySize(D, logFileCreateCounter);
            String DString = logFileCreateCounter.ToString() + "|";
            DString = DString + D.FullName + "|" + "|" + "1,0" + "|" + size.ToString() + "|" + "0,0" + "|";
            DString = DString + "0" + "|" + D.LastWriteTime + "|" + D.LastWriteTime + "|" + parent.ToString() + "|" + "-1";
            logFileCreateCounter++;
            return DString;
        }

        //Description     : Function to calculate directory size
        //Pre-Conditions  : Directory D exists
        //Post-Conditions : Size calculated       

        long CalculateDirectorySize(DirectoryInfo directory, int nI)
        {
            if (flag != 0 && DirectorySize[nI] != -1) return DirectorySize[nI];

            int cur = nodeIndex;
            DirectorySize.Add(-1);
            nodeIndex++;
            long totalSize = 0;

            // Examine all contained files.
            FileInfo[] files = directory.GetFiles();
            foreach (FileInfo file in files)
            {
                totalSize += file.Length;
                nodeIndex++;
                DirectorySize.Add(file.Length);
            }

            DirectoryInfo[] dirs = directory.GetDirectories();
            foreach (DirectoryInfo dir in dirs)
            {
                totalSize += CalculateDirectorySize(dir, nodeIndex);
            }

            return DirectorySize[cur] = totalSize;
        }


        //Description     : Function to write to logFile
        //Pre-Conditions  : logFilePath address is correct
        //Post-Conditions : logFile is written       

        public void writeToFile()
        {            
            StreamWriter SW;
            String metaDataPath = Path.Combine(profile.ProfilePath, "MetaData");
            File.Delete(metaDataPath);
            FileStream fs = File.Create(metaDataPath);
            fs.Close();

            SW = File.AppendText(metaDataPath);
            foreach (TreeNode n in arrNodes)
            {
                SW.WriteLine(n.toString());                
            }
            SW.Close();
        }

    }

    /***********************/
    /* Class MetaData ends */
    /***********************/
}
